/**
  ************************************* Copyright ******************************
  * FileName   : oled.c
  * Version    : v1.0
  * Author     : yychao
  * Date       : 2023-01-18
  * Description:
  * Function List:
  	1. ....
  	   <version>:
  <modify staff>:
  		  <data>:
   <description>:
  	2. ...
  ******************************************************************************
 */
#include "oled.h"
#include "iic.h"
#include "systick.h"
#include "log.h"
#include <rtthread.h>

#define LINE_LEN	128
#define RAM_PAGE	4
static uint8_t ram_cache[LINE_LEN][RAM_PAGE] = { 0x00 };

void oled_write_cmd(uint8_t cmd)
{
    iic_start();
    iic_send_byte(SSD1306_SLAVE_ADDR|SSD1306_IIC_WRITE);
    iic_wait_ack();
    iic_send_byte(SSD1306_IIC_CMD_MASK);
    iic_wait_ack();
    iic_send_byte(cmd);
    iic_wait_ack();
    iic_stop();
}
void oled_write_data(uint8_t data)
{
    iic_start();
    iic_send_byte(SSD1306_SLAVE_ADDR|SSD1306_IIC_WRITE);
    iic_wait_ack();
    iic_send_byte(SSD1306_IIC_DAT_MASK);
    iic_wait_ack();
    iic_send_byte(data);
    iic_wait_ack();
    iic_stop();
}

void oled_clear(void) {
    uint8_t Column = 0, Page = 0;
    for(Page = 0; Page < OLED_HEIGHT/8; Page++) {
        oled_write_cmd(0xb0 + Page);    //Set page address
        oled_write_cmd(0x00);           //Set display position - column low address
        oled_write_cmd(0x10);           //Set display position - column high address
        for(Column = 0; Column < OLED_WIDTH; Column++)
            oled_write_data(0xff);
    }
}

void oled_init(void)
{
    rt_thread_delay(200);

    oled_write_cmd(0xAE);

    oled_write_cmd(0x40);//---set low column address
    oled_write_cmd(0xB0);//---set high column address

    oled_write_cmd(0xC8);//-not offset

    oled_write_cmd(0x81);
    oled_write_cmd(0xff);

    oled_write_cmd(0xa1);

    oled_write_cmd(0xa6);

    oled_write_cmd(0xa8);
    oled_write_cmd(0x1f);

    oled_write_cmd(0xd3);
    oled_write_cmd(0x00);

    oled_write_cmd(0xd5);
    oled_write_cmd(0xf0);

    oled_write_cmd(0xd9);
    oled_write_cmd(0x22);

    oled_write_cmd(0xda);
    oled_write_cmd(0x02);

    oled_write_cmd(0xdb);
    oled_write_cmd(0x49);
    /*turn on the oled*/
    oled_write_cmd(0x8d);
    oled_write_cmd(0x14);
    oled_write_cmd(0xaf);
    rt_thread_delay(200);
    /**/
    oled_clear();
}


void LCD_RAM_INI(void) {
    memset(&ram_cache[0][0], 0xff, LINE_LEN * RAM_PAGE);
}
void LCD_POINT(uint8_t x, uint8_t y, uint8_t dis) {
    uint8_t y1 = 0;
    uint8_t y2 = 0;
    y1 = y / 8;
    y2 = y % 8;
    if (dis == 0) {
        clrbit(ram_cache[x][y1], y2);
    } else {
        setbit(ram_cache[x][y1], y2);
    }
}
void LCD_CLEAR(uint8_t dis) {
    if (dis == 0) {
        memset(&ram_cache[0][0], 0x00, LINE_LEN * RAM_PAGE);
    } else {
        memset(&ram_cache[0][0], 0xff, LINE_LEN * RAM_PAGE);
    }
}

void LCD_ADDRESS(uint8_t page, uint8_t column) {
    column = column - 1;
    page = page - 1;
    oled_write_cmd(0xb0 + page);
    oled_write_cmd(((column >> 4) & 0x0f) + 0x10);
    oled_write_cmd(column & 0x0f);
}


void LCD_UPDATE(void) {
    uint8_t i, j;
#define MOVE_OP 	(0)
#define MOVE_LEN 	(6)
    uint8_t k = 0;
    uint8_t line = 0;
    static uint8_t move_cnt = 0;
    line = move_cnt * MOVE_LEN;
    move_cnt++;
    move_cnt %= (LINE_LEN / MOVE_LEN);

    for (j = 0; j < RAM_PAGE; j++) {
        LCD_ADDRESS(j + 1, 1);
#if(MOVE_OP == 0)
        for (i = 0; i < LINE_LEN; i++) {
            oled_write_data(ram_cache[i][j]);
        }
#else
        k = line;
        for (i = 0; i < LINE_LEN; i++) {
            oled_write_data(ram_cache[k++][j]);
            k %= 128;
        }
#endif
    }
}

void LCD_ShowStr(uint16_t x, uint16_t y, uint8_t *str, FONT_SIZE size, REV reverse) {
    uint16_t x0 = x;
    uint8_t bHz = 0;     //字符或者中文
    while (*str != 0)     //数据未结束
    {
        if (!bHz) {
            if (x > (128 - size / 2) || y > (128 - size))
                return;
            if (*str > 0x80)
                bHz = 1;     //中文
            else              //字符
            {
                if (*str == 0x0D)              //换行符号
                {
                    y += size;
                    x = x0;
                    str++;
                } else {
                    if (size > 16)             //字库中没有集成12X24 16X32的英文字体,用8X16代替
                    {
                        LCD_ShowChar(x, y, *str, 16, reverse);
                        x += 8; //字符,为全字的一半
                    } else {
                        LCD_ShowChar(x, y, *str, size, reverse);
                        x += size / 2; //字符,为全字的一半
                    }
                }
                str++;

            }
        } else //中文
        {
        }
    }
}
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, FONT_SIZE size, REV reverse) {
    uint8_t temp;
    uint8_t pos, t;
    uint8_t disp1 = 0;
    uint8_t disp2 = 0;
    if (reverse != 0) {
        disp1 = 0;
        disp2 = 1;
    } else {
        disp1 = 1;
        disp2 = 0;
    }
    num = num - ' '; //得到偏移后的值
    for (pos = 0; pos < size; pos++) {
        if (size == 12)
            temp = asc2_1206[num][pos];		 //调用1206字体
        else
            temp = asc2_1608[num][pos];		 //调用1608字体
        for (t = 0; t < size / 2; t++) {
            if (temp & 0x01)
                LCD_POINT(x + t, y + pos, disp1);		 //画一个点
            else
                LCD_POINT(x + t, y + pos, disp2);
            temp >>= 1;
        }
    }
}
void LCD_LINE(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
    uint16_t t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;

    delta_x = x2 - x1;
    delta_y = y2 - y1;
    uRow = x1;
    uCol = y1;
    if (delta_x > 0)
        incx = 1;
    else if (delta_x == 0)
        incx = 0;
    else {
        incx = -1;
        delta_x = -delta_x;
    }
    if (delta_y > 0)
        incy = 1;
    else if (delta_y == 0)
        incy = 0;
    else {
        incy = -1;
        delta_y = -delta_y;
    }
    if (delta_x > delta_y)
        distance = delta_x;
    else
        distance = delta_y;
    for (t = 0; t <= distance + 1; t++) {
        LCD_POINT(uRow, uCol, 1);
        xerr += delta_x;
        yerr += delta_y;
        if (xerr > distance) {
            xerr -= distance;
            uRow += incx;
        }
        if (yerr > distance) {
            yerr -= distance;
            uCol += incy;
        }
    }
}
void LCD_TRIANGEL(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
                  uint16_t x2, uint16_t y2) {
    LCD_LINE(x0, y0, x1, y1);
    LCD_LINE(x1, y1, x2, y2);
    LCD_LINE(x2, y2, x0, y0);
}
void LCD_RECTANGLE(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
    LCD_LINE(x1, y1, x2, y1);
    LCD_LINE(x1, y1, x1, y2);
    LCD_LINE(x1, y2, x2, y2);
    LCD_LINE(x2, y1, x2, y2);
}
void LCD_CIRCLE_8(int xc, int yc, int x, int y) {
    LCD_POINT(xc + x, yc + y, 1);
    LCD_POINT(xc - x, yc + y, 1);
    LCD_POINT(xc + x, yc - y, 1);
    LCD_POINT(xc - x, yc - y, 1);
    LCD_POINT(xc + y, yc + x, 1);
    LCD_POINT(xc - y, yc + x, 1);
    LCD_POINT(xc + y, yc - x, 1);
    LCD_POINT(xc - y, yc - x, 1);
}
void LCD_CIRCLE(int xc, int yc, int r) {
    int x = 0;
    int d = 0;
    int y = r;
    d = 3 - 2 * r;
    while (x <= y) {
        LCD_CIRCLE_8(xc, yc, x, y);
        if (d < 0) {
            d = d + 4 * x + 6;
        } else {
            d = d + 4 * (x - y) + 10;
            y--;
        }
        x++;
    }
}

